#include "mainwindow.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QMessageBox>

// 构造函数：初始化界面与TCP客户端
MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
{
    // 创建主窗口的中心部件并设置
    QWidget *centralWidget = new QWidget(this);
    this->setCentralWidget(centralWidget);

    // 初始化 TCP 客户端套接字
    tcpclient = new QTcpSocket(this);

    // 初始化控件
    comboBoxIp = new QComboBox(this);  // 用于输入或选择服务器 IP 地址
    spinBoxPort = new QSpinBox(this); // 用于输入服务器端口
    spinBoxPort->setMaximum(65535);   // 设置端口最大值
    spinBoxPort->setValue(6688);      // 默认端口

    pushButtonConnect = new QPushButton("连接服务器", this);      // 连接按钮
    pushButtonDisconnect = new QPushButton("断开服务器", this);    // 断开按钮
    pushButtonDisconnect->setEnabled(false);                      // 初始时不可用

    lineEditInputMsg = new QLineEdit(this);      // 输入发送消息的文本框
    pushButtonSend = new QPushButton("发送消息", this);  // 发送按钮
    plainTextEditDispMsg = new QPlainTextEdit(this);     // 显示消息的文本区域
    plainTextEditDispMsg->setReadOnly(true);     // 设置为只读

    // 获取并设置本机 IP
    QString strip = getLocalIp();
    comboBoxIp->addItem(strip);

    // 主布局
    QVBoxLayout *mainLayout = new QVBoxLayout;

    // 顶部布局：IP、端口、连接、断开按钮
    QHBoxLayout *topLayout = new QHBoxLayout;
    topLayout->addWidget(new QLabel("服务器地址："));
    topLayout->addWidget(comboBoxIp);
    topLayout->addWidget(new QLabel("服务器端口："));
    topLayout->addWidget(spinBoxPort);
    topLayout->addWidget(pushButtonConnect);
    topLayout->addWidget(pushButtonDisconnect);
    mainLayout->addLayout(topLayout);

    // 中间布局：消息输入框和发送按钮
    QHBoxLayout *sendLayout = new QHBoxLayout;
    sendLayout->addWidget(lineEditInputMsg);
    sendLayout->addWidget(pushButtonSend);
    mainLayout->addLayout(sendLayout);

    // 底部：显示区域
    mainLayout->addWidget(plainTextEditDispMsg);

    // 设置布局到中心窗口
    centralWidget->setLayout(mainLayout);
    this->setWindowTitle("TCP客户端程序--测试版"); // 设置窗口标题
    this->resize(700, 400);                       // 设置窗口大小

    // 按钮点击事件连接到槽函数
    connect(pushButtonConnect, &QPushButton::clicked, this, &MainWindow::onConnectClicked);
    connect(pushButtonDisconnect, &QPushButton::clicked, this, &MainWindow::onDisconnectClicked);
    connect(pushButtonSend, &QPushButton::clicked, this, &MainWindow::onSendClicked);

    // 套接字相关信号连接到槽函数
    connect(tcpclient, &QTcpSocket::connected, this, &MainWindow::connectFunc);           // 连接成功
    connect(tcpclient, &QTcpSocket::disconnected, this, &MainWindow::disconnectFunc);     // 连接断开
    connect(tcpclient, &QTcpSocket::readyRead, this, &MainWindow::socketReadData);        // 有数据可读
}

// 析构函数
MainWindow::~MainWindow() {}

// 获取本地IP地址（优先IPv4）
QString MainWindow::getLocalIp()
{
    QString hostname = QHostInfo::localHostName();         // 获取本机主机名
    QHostInfo hostinfo = QHostInfo::fromName(hostname);    // 获取主机信息
    QString localip = "";

    QList<QHostAddress> addlist = hostinfo.addresses();    // 获取所有IP地址
    for (const QHostAddress &addr : addlist)
    {
        if (addr.protocol() == QAbstractSocket::IPv4Protocol) // 只选择IPv4地址
        {
            localip = addr.toString();   // 转换为字符串
            break;                       // 找到一个IPv4就退出
        }
    }
    return localip;
}

// 重写关闭事件，在关闭窗口时断开TCP连接
void MainWindow::closeEvent(QCloseEvent *event)
{
    if (tcpclient->state() == QAbstractSocket::ConnectedState)
    {
        tcpclient->disconnectFromHost();  // 主动断开连接
    }
    event->accept(); // 接受关闭事件
}

// 点击“连接服务器”按钮
void MainWindow::onConnectClicked()
{
    QString addr = comboBoxIp->currentText();      // 获取IP
    quint16 port = spinBoxPort->value();           // 获取端口
    tcpclient->connectToHost(addr, port);          // 尝试连接服务器
}

// 点击“断开服务器”按钮
void MainWindow::onDisconnectClicked()
{
    if (tcpclient->state() == QAbstractSocket::ConnectedState)
        tcpclient->disconnectFromHost();           // 断开连接
}

// 点击“发送消息”按钮
void MainWindow::onSendClicked()
{
    QString strmsg = lineEditInputMsg->text();     // 获取输入内容
    if (strmsg.isEmpty()) return;                  // 空内容不发送

    plainTextEditDispMsg->appendPlainText("[out]: " + strmsg); // 显示到消息框
    lineEditInputMsg->clear();                     // 清空输入框

    QByteArray data = strmsg.toUtf8();             // 转为字节数组
    data.append('\n');                             // 添加换行符作为结束标志
    tcpclient->write(data);                        // 发送数据
}

// 当成功连接服务器后触发
void MainWindow::connectFunc()
{
    plainTextEditDispMsg->appendPlainText("********** 已连接到服务器 **********");
    plainTextEditDispMsg->appendPlainText("peer address: " + tcpclient->peerAddress().toString());
    plainTextEditDispMsg->appendPlainText("peer port: " + QString::number(tcpclient->peerPort()));

    pushButtonConnect->setEnabled(false);  // 禁用连接按钮
    pushButtonDisconnect->setEnabled(true); // 启用断开按钮
}

// 断开连接时触发
void MainWindow::disconnectFunc()
{
    plainTextEditDispMsg->appendPlainText("********** 已断开与服务器连接 **********");

    pushButtonConnect->setEnabled(true);   // 启用连接按钮
    pushButtonDisconnect->setEnabled(false); // 禁用断开按钮
}

// 有数据可读时触发，读取服务器发来的数据
void MainWindow::socketReadData()
{
    while (tcpclient->canReadLine()) // 如果有完整一行数据可读
    {
        QString line = tcpclient->readLine(); // 读取一行
        plainTextEditDispMsg->appendPlainText("[in]: " + line.trimmed()); // 显示到文本区
    }
}
/*
 * 这个 Qt 案例完整实现了一个TCP 客户端程序的核心功能，包括：
    获取本机 IP；
    用户输入服务器地址和端口；
    连接/断开服务器；
    发送消息到服务器；
    接收并显示服务器返回的消息；
    界面不依赖 .ui 文件，完全通过代码构建。
 * */